package documentclassifier;

import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.io.File;
import java.util.AbstractMap;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.ResourceBundle;
import java.util.prefs.Preferences;
import javax.swing.JFileChooser;
import javax.swing.JTextField;
import javax.swing.filechooser.FileFilter;
import org.jdesktop.application.Action;
import org.jdesktop.application.FrameView;

/**
 * This class represents the JDialog used to modify the program's preferences, such as
 * - The scraper used to extract the features (terms) from documents.
 * - The metric used to calculate the distance between documents.
 * - Etc...
 * 
 * @author      Salvo Danilo Giuffrida (salvod.giuffrida@gmail.com)
 */
public class PreferencesDialog extends javax.swing.JDialog {

    private static final long serialVersionUID = 0;
    private final DocumentClassifierApp application = DocumentClassifierApp.getApplication();
    private final Preferences preferences = application.getPreferences();
    private ResourceBundle preferencesDialogResources = java.util.ResourceBundle.getBundle("documentclassifier/resources/PreferencesDialog");
    /**
     * An instance of the class {@link MapDefaultPreferences} is necessary to refer, in an
     * indirect way, to the names of the various preferences, and if necessary to their
     * default values.
     */
    private final MapDefaultPreferences mapPreferences = application.getMapPreferences();
    private String trainingSetDirectory,  stopWordsList,  logFile;

    /**
     * Constructor that creates a new PreferencesDialog.
     * 
     * @param   parent      The frame father of this JDialog.
     * @param   modal       A boolean indicating if the JDialog should be modal or not.
     */
    PreferencesDialog(FrameView parent, boolean modal) {
        super(parent.getFrame(), modal);
        initComponents();
        preferences.addPreferenceChangeListener(application);
        preferences.addPreferenceChangeListener((DocumentClassifierView) parent);
        initializeInterface(false);
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {
        bindingGroup = new org.jdesktop.beansbinding.BindingGroup();

        groupMetrics = new javax.swing.ButtonGroup();
        buttonOK = new javax.swing.JButton();
        buttonCancel = new javax.swing.JButton();
        buttonReset = new javax.swing.JButton();
        tabbelPanePreferences = new javax.swing.JTabbedPane();
        panelTrainingSet = new javax.swing.JPanel();
        labelTrainingSetDirectory = new javax.swing.JLabel();
        fieldTrainingSetDirectory = new javax.swing.JTextField();
        buttonBrowseTrainingSetDirectory = new javax.swing.JButton();
        panelPreprocessing = new javax.swing.JPanel();
        labelScraper = new javax.swing.JLabel();
        comboBoxScraper = new javax.swing.JComboBox();
        separatorScraperPreprocessing = new javax.swing.JSeparator();
        labelPreprocessing = new javax.swing.JLabel();
        checkBoxStopWords = new javax.swing.JCheckBox();
        labelStopWords = new javax.swing.JLabel();
        fieldStopWords = new javax.swing.JTextField();
        buttonBrowseStopWords = new javax.swing.JButton();
        checkBoxStemming = new javax.swing.JCheckBox();
        labelCurrentStemmer = new javax.swing.JLabel();
        comboBoxStemmers = new javax.swing.JComboBox();
        panelClassification = new javax.swing.JPanel();
        buttonTFIDF = new javax.swing.JRadioButton();
        buttonBhattacharrya = new javax.swing.JRadioButton();
        labelMetric = new javax.swing.JLabel();
        sliderKNN = new javax.swing.JSlider();
        labelKNNTitle = new javax.swing.JLabel();
        separatorMetricKNN = new javax.swing.JSeparator();
        labelKNNValue = new javax.swing.JLabel();
        panelValidation = new javax.swing.JPanel();
        sliderKFold = new javax.swing.JSlider();
        labelKFoldTitle = new javax.swing.JLabel();
        separatorKFoldLogging = new javax.swing.JSeparator();
        checkBoxStratified = new javax.swing.JCheckBox();
        checkBoxVisualizeListDocuments = new javax.swing.JCheckBox();
        labelKFoldValue = new javax.swing.JLabel();
        separatorKNNMaximumKFold = new javax.swing.JSeparator();
        labelKNNMaximumTitle = new javax.swing.JLabel();
        labelKNNMaximumValue = new javax.swing.JLabel();
        sliderKNNMaximum = new javax.swing.JSlider();
        checkBoxVisualizeCurrentDocument = new javax.swing.JCheckBox();
        labelLogFile = new javax.swing.JLabel();
        fieldLogFile = new javax.swing.JTextField();
        buttonBrowseLogFile = new javax.swing.JButton();
        separatorLogFileVisualize = new javax.swing.JSeparator();
        checkBoxLogging = new javax.swing.JCheckBox();
        checkBoxOverwriteLogFile = new javax.swing.JCheckBox();

        FormListener formListener = new FormListener();

        setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
        org.jdesktop.application.ResourceMap resourceMap = org.jdesktop.application.Application.getInstance(documentclassifier.DocumentClassifierApp.class).getContext().getResourceMap(PreferencesDialog.class);
        setTitle(resourceMap.getString("Form.title")); // NOI18N
        setLocationByPlatform(true);
        setModal(true);
        setName("Form"); // NOI18N

        javax.swing.ActionMap actionMap = org.jdesktop.application.Application.getInstance(documentclassifier.DocumentClassifierApp.class).getContext().getActionMap(PreferencesDialog.class, this);
        buttonOK.setAction(actionMap.get("OK")); // NOI18N
        buttonOK.setToolTipText(resourceMap.getString("buttonOK.toolTipText")); // NOI18N
        buttonOK.setName("buttonOK"); // NOI18N

        buttonCancel.setAction(actionMap.get("cancel")); // NOI18N
        buttonCancel.setToolTipText(resourceMap.getString("buttonCancel.toolTipText")); // NOI18N
        buttonCancel.setName("buttonCancel"); // NOI18N

        buttonReset.setAction(actionMap.get("reset")); // NOI18N
        buttonReset.setToolTipText(resourceMap.getString("buttonReset.toolTipText")); // NOI18N
        buttonReset.setName("buttonReset"); // NOI18N

        tabbelPanePreferences.setName("tabbelPanePreferences"); // NOI18N

        panelTrainingSet.setName("panelTrainingSet"); // NOI18N

        labelTrainingSetDirectory.setText(resourceMap.getString("labelTrainingSetDirectory.text")); // NOI18N
        labelTrainingSetDirectory.setName("labelTrainingSetDirectory"); // NOI18N

        fieldTrainingSetDirectory.setToolTipText(resourceMap.getString("fieldTrainingSetDirectory.toolTipText")); // NOI18N
        fieldTrainingSetDirectory.setName("fieldTrainingSetDirectory"); // NOI18N
        fieldTrainingSetDirectory.addFocusListener(formListener);

        buttonBrowseTrainingSetDirectory.setText(resourceMap.getString("buttonBrowseTrainingSetDirectory.text")); // NOI18N
        buttonBrowseTrainingSetDirectory.setName("buttonBrowseTrainingSetDirectory"); // NOI18N
        buttonBrowseTrainingSetDirectory.addActionListener(formListener);

        javax.swing.GroupLayout panelTrainingSetLayout = new javax.swing.GroupLayout(panelTrainingSet);
        panelTrainingSet.setLayout(panelTrainingSetLayout);
        panelTrainingSetLayout.setHorizontalGroup(
            panelTrainingSetLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(panelTrainingSetLayout.createSequentialGroup()
                .addContainerGap()
                .addComponent(labelTrainingSetDirectory)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(fieldTrainingSetDirectory, javax.swing.GroupLayout.DEFAULT_SIZE, 377, Short.MAX_VALUE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(buttonBrowseTrainingSetDirectory)
                .addContainerGap())
        );
        panelTrainingSetLayout.setVerticalGroup(
            panelTrainingSetLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(panelTrainingSetLayout.createSequentialGroup()
                .addContainerGap()
                .addGroup(panelTrainingSetLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(labelTrainingSetDirectory)
                    .addComponent(buttonBrowseTrainingSetDirectory)
                    .addComponent(fieldTrainingSetDirectory, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addContainerGap(317, Short.MAX_VALUE))
        );

        tabbelPanePreferences.addTab(resourceMap.getString("panelTrainingSet.TabConstraints.tabTitle"), panelTrainingSet); // NOI18N

        panelPreprocessing.setName("panelPreprocessing"); // NOI18N

        labelScraper.setLabelFor(comboBoxScraper);
        labelScraper.setText(resourceMap.getString("labelScraper.text")); // NOI18N
        labelScraper.setName("labelScraper"); // NOI18N

        comboBoxScraper.setToolTipText(resourceMap.getString("comboBoxScraper.toolTipText")); // NOI18N
        comboBoxScraper.setName("comboBoxScraper"); // NOI18N

        separatorScraperPreprocessing.setName("separatorScraperPreprocessing"); // NOI18N

        labelPreprocessing.setText(resourceMap.getString("labelPreprocessing.text")); // NOI18N
        labelPreprocessing.setToolTipText(resourceMap.getString("labelPreprocessing.toolTipText")); // NOI18N
        labelPreprocessing.setName("labelPreprocessing"); // NOI18N

        checkBoxStopWords.setSelected(true);
        checkBoxStopWords.setText(resourceMap.getString("checkBoxStopWords.text")); // NOI18N
        checkBoxStopWords.setName("checkBoxStopWords"); // NOI18N
        checkBoxStopWords.addChangeListener(formListener);

        labelStopWords.setLabelFor(fieldStopWords);
        labelStopWords.setText(resourceMap.getString("labelStopWords.text")); // NOI18N
        labelStopWords.setName("labelStopWords"); // NOI18N

        fieldStopWords.setToolTipText(resourceMap.getString("fieldStopWords.toolTipText")); // NOI18N
        fieldStopWords.setName("fieldStopWords"); // NOI18N
        fieldStopWords.addFocusListener(formListener);

        buttonBrowseStopWords.setText(resourceMap.getString("buttonBrowseStopWords.text")); // NOI18N
        buttonBrowseStopWords.setName("buttonBrowseStopWords"); // NOI18N
        buttonBrowseStopWords.addActionListener(formListener);

        checkBoxStemming.setSelected(true);
        checkBoxStemming.setText(resourceMap.getString("checkBoxStemming.text")); // NOI18N
        checkBoxStemming.setName("checkBoxStemming"); // NOI18N
        checkBoxStemming.addChangeListener(formListener);

        labelCurrentStemmer.setLabelFor(checkBoxStemming);
        labelCurrentStemmer.setText(resourceMap.getString("labelCurrentStemmer.text")); // NOI18N
        labelCurrentStemmer.setName("labelCurrentStemmer"); // NOI18N

        comboBoxStemmers.setToolTipText(resourceMap.getString("comboBoxStemmers.toolTipText")); // NOI18N
        comboBoxStemmers.setName("comboBoxStemmers"); // NOI18N

        javax.swing.GroupLayout panelPreprocessingLayout = new javax.swing.GroupLayout(panelPreprocessing);
        panelPreprocessing.setLayout(panelPreprocessingLayout);
        panelPreprocessingLayout.setHorizontalGroup(
            panelPreprocessingLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(panelPreprocessingLayout.createSequentialGroup()
                .addContainerGap()
                .addGroup(panelPreprocessingLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(separatorScraperPreprocessing, javax.swing.GroupLayout.DEFAULT_SIZE, 589, Short.MAX_VALUE)
                    .addGroup(panelPreprocessingLayout.createSequentialGroup()
                        .addComponent(labelScraper)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(comboBoxScraper, 0, 524, Short.MAX_VALUE))
                    .addComponent(labelPreprocessing)
                    .addGroup(panelPreprocessingLayout.createSequentialGroup()
                        .addGap(12, 12, 12)
                        .addGroup(panelPreprocessingLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addGroup(panelPreprocessingLayout.createSequentialGroup()
                                .addGap(12, 12, 12)
                                .addComponent(labelStopWords, javax.swing.GroupLayout.PREFERRED_SIZE, 110, javax.swing.GroupLayout.PREFERRED_SIZE)
                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                .addComponent(fieldStopWords, javax.swing.GroupLayout.DEFAULT_SIZE, 380, Short.MAX_VALUE)
                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                .addComponent(buttonBrowseStopWords))
                            .addComponent(checkBoxStopWords)
                            .addComponent(checkBoxStemming)
                            .addGroup(panelPreprocessingLayout.createSequentialGroup()
                                .addGap(12, 12, 12)
                                .addComponent(labelCurrentStemmer)
                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                .addComponent(comboBoxStemmers, 0, 493, Short.MAX_VALUE)))))
                .addContainerGap())
        );
        panelPreprocessingLayout.setVerticalGroup(
            panelPreprocessingLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(panelPreprocessingLayout.createSequentialGroup()
                .addContainerGap()
                .addGroup(panelPreprocessingLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(labelScraper)
                    .addComponent(comboBoxScraper, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addComponent(separatorScraperPreprocessing, javax.swing.GroupLayout.PREFERRED_SIZE, 10, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(labelPreprocessing)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(checkBoxStopWords)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(panelPreprocessingLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(labelStopWords)
                    .addComponent(fieldStopWords, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(buttonBrowseStopWords))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(checkBoxStemming)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(panelPreprocessingLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(labelCurrentStemmer)
                    .addComponent(comboBoxStemmers, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addContainerGap(156, Short.MAX_VALUE))
        );

        tabbelPanePreferences.addTab(resourceMap.getString("panelPreprocessing.TabConstraints.tabTitle"), panelPreprocessing); // NOI18N

        panelClassification.setName("panelClassification"); // NOI18N

        groupMetrics.add(buttonTFIDF);
        buttonTFIDF.setSelected(true);
        buttonTFIDF.setText(resourceMap.getString("buttonTFIDF.text")); // NOI18N
        buttonTFIDF.setName("buttonTFIDF"); // NOI18N

        groupMetrics.add(buttonBhattacharrya);
        buttonBhattacharrya.setText(resourceMap.getString("buttonBhattacharrya.text")); // NOI18N
        buttonBhattacharrya.setName("buttonBhattacharrya"); // NOI18N

        labelMetric.setText(resourceMap.getString("labelMetric.text")); // NOI18N
        labelMetric.setToolTipText(resourceMap.getString("labelMetric.toolTipText")); // NOI18N
        labelMetric.setName("labelMetric"); // NOI18N

        sliderKNN.setMaximum(application.getKNNMaximum());
        sliderKNN.setMinimum(1);
        sliderKNN.setToolTipText(resourceMap.getString("sliderKNN.toolTipText")); // NOI18N
        sliderKNN.setValue(sliderKNN.getMinimum());
        sliderKNN.setName("sliderKNN"); // NOI18N

        labelKNNTitle.setText(resourceMap.getString("labelKNNTitle.text")); // NOI18N
        labelKNNTitle.setName("labelKNNTitle"); // NOI18N

        separatorMetricKNN.setName("separatorMetricKNN"); // NOI18N

        labelKNNValue.setName("labelKNNValue"); // NOI18N

        org.jdesktop.beansbinding.Binding binding = org.jdesktop.beansbinding.Bindings.createAutoBinding(org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ_WRITE, sliderKNN, org.jdesktop.beansbinding.ELProperty.create("${value}"), labelKNNValue, org.jdesktop.beansbinding.BeanProperty.create("text"));
        bindingGroup.addBinding(binding);

        javax.swing.GroupLayout panelClassificationLayout = new javax.swing.GroupLayout(panelClassification);
        panelClassification.setLayout(panelClassificationLayout);
        panelClassificationLayout.setHorizontalGroup(
            panelClassificationLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, panelClassificationLayout.createSequentialGroup()
                .addContainerGap()
                .addGroup(panelClassificationLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
                    .addComponent(separatorMetricKNN, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 589, Short.MAX_VALUE)
                    .addGroup(javax.swing.GroupLayout.Alignment.LEADING, panelClassificationLayout.createSequentialGroup()
                        .addComponent(labelMetric)
                        .addGap(7, 7, 7)
                        .addGroup(panelClassificationLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addComponent(buttonBhattacharrya)
                            .addComponent(buttonTFIDF)))
                    .addGroup(javax.swing.GroupLayout.Alignment.LEADING, panelClassificationLayout.createSequentialGroup()
                        .addComponent(labelKNNTitle, javax.swing.GroupLayout.PREFERRED_SIZE, 37, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(labelKNNValue, javax.swing.GroupLayout.PREFERRED_SIZE, 35, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(sliderKNN, javax.swing.GroupLayout.DEFAULT_SIZE, 499, Short.MAX_VALUE)))
                .addContainerGap())
        );
        panelClassificationLayout.setVerticalGroup(
            panelClassificationLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(panelClassificationLayout.createSequentialGroup()
                .addContainerGap()
                .addGroup(panelClassificationLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(buttonTFIDF)
                    .addComponent(labelMetric))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(buttonBhattacharrya)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(separatorMetricKNN, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(panelClassificationLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(panelClassificationLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                        .addComponent(labelKNNTitle, javax.swing.GroupLayout.PREFERRED_SIZE, 20, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addComponent(labelKNNValue))
                    .addComponent(sliderKNN, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addContainerGap(238, Short.MAX_VALUE))
        );

        tabbelPanePreferences.addTab(resourceMap.getString("panelClassification.TabConstraints.tabTitle"), panelClassification); // NOI18N

        panelValidation.setName("panelValidation"); // NOI18N

        sliderKFold.setMaximum(application.getKFoldMaximum());
        sliderKFold.setMinimum(application.getKFoldMinimum());
        sliderKFold.setToolTipText(resourceMap.getString("sliderKFold.toolTipText")); // NOI18N
        sliderKFold.setValue(application.getKFold(false));
        sliderKFold.setName("sliderKFold"); // NOI18N
        sliderKFold.addChangeListener(formListener);

        labelKFoldTitle.setText(resourceMap.getString("labelKFoldTitle.text")); // NOI18N
        labelKFoldTitle.setName("labelKFoldTitle"); // NOI18N

        separatorKFoldLogging.setName("separatorKFoldLogging"); // NOI18N

        checkBoxStratified.setText(resourceMap.getString("checkBoxStratified.text")); // NOI18N
        checkBoxStratified.setToolTipText(resourceMap.getString("checkBoxStratified.toolTipText")); // NOI18N
        checkBoxStratified.setName("checkBoxStratified"); // NOI18N
        checkBoxStratified.addChangeListener(formListener);

        checkBoxVisualizeListDocuments.setText(resourceMap.getString("checkBoxVisualizeListDocuments.text")); // NOI18N
        checkBoxVisualizeListDocuments.setToolTipText(resourceMap.getString("checkBoxVisualizeListDocuments.toolTipText")); // NOI18N
        checkBoxVisualizeListDocuments.setName("checkBoxVisualizeListDocuments"); // NOI18N

        labelKFoldValue.setName("labelKFoldValue"); // NOI18N

        binding = org.jdesktop.beansbinding.Bindings.createAutoBinding(org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ_WRITE, sliderKFold, org.jdesktop.beansbinding.ELProperty.create("${value}"), labelKFoldValue, org.jdesktop.beansbinding.BeanProperty.create("text"));
        bindingGroup.addBinding(binding);

        separatorKNNMaximumKFold.setName("separatorKNNMaximumKFold"); // NOI18N

        labelKNNMaximumTitle.setText(resourceMap.getString("labelKNNMaximumTitle.text")); // NOI18N
        labelKNNMaximumTitle.setName("labelKNNMaximumTitle"); // NOI18N

        labelKNNMaximumValue.setName("labelKNNMaximumValue"); // NOI18N

        binding = org.jdesktop.beansbinding.Bindings.createAutoBinding(org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ_WRITE, sliderKNNMaximum, org.jdesktop.beansbinding.ELProperty.create("${value}"), labelKNNMaximumValue, org.jdesktop.beansbinding.BeanProperty.create("text"));
        bindingGroup.addBinding(binding);

        sliderKNNMaximum.setMaximum((application.getTrainingSetSize()/application.getKFold(false))*(application.getKFold(false)-1));
        sliderKNNMaximum.setMinimum(sliderKNN.getMinimum());
        sliderKNNMaximum.setToolTipText(resourceMap.getString("sliderKNNMaximum.toolTipText")); // NOI18N
        sliderKNNMaximum.setValue(sliderKNNMaximum.getMinimum());
        sliderKNNMaximum.setName("sliderKNNMaximum"); // NOI18N

        checkBoxVisualizeCurrentDocument.setText(resourceMap.getString("checkBoxVisualizeCurrentDocument.text")); // NOI18N
        checkBoxVisualizeCurrentDocument.setToolTipText(resourceMap.getString("checkBoxVisualizeCurrentDocument.toolTipText")); // NOI18N
        checkBoxVisualizeCurrentDocument.setName("checkBoxVisualizeCurrentDocument"); // NOI18N

        labelLogFile.setText(resourceMap.getString("labelLogFile.text")); // NOI18N
        labelLogFile.setName("labelLogFile"); // NOI18N

        fieldLogFile.setToolTipText(resourceMap.getString("fieldLogFile.toolTipText")); // NOI18N
        fieldLogFile.setName("fieldLogFile"); // NOI18N

        buttonBrowseLogFile.setText(resourceMap.getString("buttonBrowseLogFile.text")); // NOI18N
        buttonBrowseLogFile.setName("buttonBrowseLogFile"); // NOI18N
        buttonBrowseLogFile.addActionListener(formListener);

        separatorLogFileVisualize.setName("separatorLogFileVisualize"); // NOI18N

        checkBoxLogging.setSelected(true);
        checkBoxLogging.setText(resourceMap.getString("checkBoxLogging.text")); // NOI18N
        checkBoxLogging.setToolTipText(resourceMap.getString("checkBoxLogging.toolTipText")); // NOI18N
        checkBoxLogging.setName("checkBoxLogging"); // NOI18N
        checkBoxLogging.addItemListener(formListener);

        checkBoxOverwriteLogFile.setSelected(true);
        checkBoxOverwriteLogFile.setText(resourceMap.getString("checkBoxOverwriteLogFile.text")); // NOI18N
        checkBoxOverwriteLogFile.setToolTipText(resourceMap.getString("checkBoxOverwriteLogFile.toolTipText")); // NOI18N
        checkBoxOverwriteLogFile.setName("checkBoxOverwriteLogFile"); // NOI18N

        javax.swing.GroupLayout panelValidationLayout = new javax.swing.GroupLayout(panelValidation);
        panelValidation.setLayout(panelValidationLayout);
        panelValidationLayout.setHorizontalGroup(
            panelValidationLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, panelValidationLayout.createSequentialGroup()
                .addContainerGap()
                .addGroup(panelValidationLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
                    .addComponent(separatorLogFileVisualize, javax.swing.GroupLayout.DEFAULT_SIZE, 589, Short.MAX_VALUE)
                    .addGroup(javax.swing.GroupLayout.Alignment.LEADING, panelValidationLayout.createSequentialGroup()
                        .addGap(12, 12, 12)
                        .addComponent(checkBoxStratified))
                    .addGroup(javax.swing.GroupLayout.Alignment.LEADING, panelValidationLayout.createSequentialGroup()
                        .addComponent(labelKFoldTitle)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(labelKFoldValue, javax.swing.GroupLayout.PREFERRED_SIZE, 33, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(sliderKFold, javax.swing.GroupLayout.DEFAULT_SIZE, 395, Short.MAX_VALUE))
                    .addComponent(separatorKFoldLogging, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 589, Short.MAX_VALUE)
                    .addGroup(javax.swing.GroupLayout.Alignment.LEADING, panelValidationLayout.createSequentialGroup()
                        .addComponent(labelKNNMaximumTitle)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(labelKNNMaximumValue, javax.swing.GroupLayout.PREFERRED_SIZE, 30, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(sliderKNNMaximum, javax.swing.GroupLayout.DEFAULT_SIZE, 447, Short.MAX_VALUE))
                    .addComponent(separatorKNNMaximumKFold, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 589, Short.MAX_VALUE)
                    .addComponent(checkBoxLogging, javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(panelValidationLayout.createSequentialGroup()
                        .addGap(12, 12, 12)
                        .addComponent(labelLogFile)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(fieldLogFile, javax.swing.GroupLayout.DEFAULT_SIZE, 366, Short.MAX_VALUE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(buttonBrowseLogFile)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(checkBoxOverwriteLogFile))
                    .addComponent(checkBoxVisualizeCurrentDocument, javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(checkBoxVisualizeListDocuments, javax.swing.GroupLayout.Alignment.LEADING))
                .addContainerGap())
        );
        panelValidationLayout.setVerticalGroup(
            panelValidationLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(panelValidationLayout.createSequentialGroup()
                .addGroup(panelValidationLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(panelValidationLayout.createSequentialGroup()
                        .addContainerGap()
                        .addGroup(panelValidationLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addGroup(panelValidationLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                                .addComponent(labelKNNMaximumTitle)
                                .addComponent(labelKNNMaximumValue))
                            .addComponent(sliderKNNMaximum, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                        .addComponent(separatorKNNMaximumKFold, javax.swing.GroupLayout.PREFERRED_SIZE, 10, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addGroup(panelValidationLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addGroup(panelValidationLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                                .addComponent(labelKFoldTitle)
                                .addComponent(labelKFoldValue))
                            .addComponent(sliderKFold, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(checkBoxStratified)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(separatorKFoldLogging, javax.swing.GroupLayout.PREFERRED_SIZE, 10, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(checkBoxLogging))
                    .addGroup(panelValidationLayout.createSequentialGroup()
                        .addGap(199, 199, 199)
                        .addGroup(panelValidationLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                            .addComponent(labelLogFile)
                            .addComponent(fieldLogFile, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                            .addComponent(buttonBrowseLogFile)
                            .addComponent(checkBoxOverwriteLogFile))))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addComponent(separatorLogFileVisualize, javax.swing.GroupLayout.PREFERRED_SIZE, 10, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(checkBoxVisualizeCurrentDocument)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(checkBoxVisualizeListDocuments)
                .addContainerGap(52, Short.MAX_VALUE))
        );

        tabbelPanePreferences.addTab(resourceMap.getString("panelValidation.TabConstraints.tabTitle"), panelValidation); // NOI18N

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addComponent(buttonOK)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(buttonCancel)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(buttonReset)
                .addContainerGap(439, Short.MAX_VALUE))
            .addComponent(tabbelPanePreferences, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 625, Short.MAX_VALUE)
        );

        layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {buttonCancel, buttonOK, buttonReset});

        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                .addComponent(tabbelPanePreferences, javax.swing.GroupLayout.DEFAULT_SIZE, 397, Short.MAX_VALUE)
                .addGap(18, 18, 18)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(buttonOK)
                    .addComponent(buttonCancel)
                    .addComponent(buttonReset))
                .addContainerGap())
        );

        bindingGroup.bind();

        pack();
    }

    // Code for dispatching events from components to event handlers.

    private class FormListener implements java.awt.event.ActionListener, java.awt.event.FocusListener, java.awt.event.ItemListener, javax.swing.event.ChangeListener {
        FormListener() {}
        public void actionPerformed(java.awt.event.ActionEvent evt) {
            if (evt.getSource() == buttonBrowseTrainingSetDirectory) {
                PreferencesDialog.this.browse(evt);
            }
            else if (evt.getSource() == buttonBrowseStopWords) {
                PreferencesDialog.this.browse(evt);
            }
            else if (evt.getSource() == buttonBrowseLogFile) {
                PreferencesDialog.this.browse(evt);
            }
        }

        public void focusGained(java.awt.event.FocusEvent evt) {
        }

        public void focusLost(java.awt.event.FocusEvent evt) {
            if (evt.getSource() == fieldTrainingSetDirectory) {
                PreferencesDialog.this.checkPath(evt);
            }
            else if (evt.getSource() == fieldStopWords) {
                PreferencesDialog.this.checkPath(evt);
            }
        }

        public void itemStateChanged(java.awt.event.ItemEvent evt) {
            if (evt.getSource() == checkBoxLogging) {
                PreferencesDialog.this.checkBoxLoggingItemStateChanged(evt);
            }
        }

        public void stateChanged(javax.swing.event.ChangeEvent evt) {
            if (evt.getSource() == checkBoxStopWords) {
                PreferencesDialog.this.checkBoxStopWordsStateChanged(evt);
            }
            else if (evt.getSource() == checkBoxStemming) {
                PreferencesDialog.this.checkBoxStemmingStateChanged(evt);
            }
            else if (evt.getSource() == sliderKFold) {
                PreferencesDialog.this.fixKFold(evt);
            }
            else if (evt.getSource() == checkBoxStratified) {
                PreferencesDialog.this.fixKFold(evt);
            }
        }
    }// </editor-fold>//GEN-END:initComponents

    /**
     * This method updates the value of the preference specified in the 1st parameter
     * with the new value, specified in the 3rd parameter, if it's different from the
     * current value.
     * 
     * @param   preferenceName      The name of the preference whose value must be updated.
     * @param   defaultValue        Its default value.
     * @param   updatedValue        The new value that must be assigned to it.
     */
    private void updatePreference(String preferenceName, String defaultValue, String updatedValue) {

        if (!preferences.get(preferenceName, defaultValue).equals(updatedValue)) {
            preferences.put(preferenceName, updatedValue);
        }
    }

    /**
     * This action is called each time that the user presses the button 'Cancel' in the GUI.
     * Its only task is to close the JDialog.
     */
    @Action
    public void cancel() {
        dispose();
    }

    /**
     * This method is called during initialization of the GUI, each time that the user decides to open this JDialog,
     * clicking on the menù item 'Modify'->'Preferences' in the menù bar.
     * <p>
     * It initializes the various components of the GUI, using the values of the various preferences, read from
     * the class {@link DocumentClassifierApp}, which represents the application's core.
     * 
     * @param reset             Boolean value, which indicates if the components of the GUI must be (re)initialized
     *                          with the preferences' default values, or if instead with their current values.
     */
    private void initializeInterface(boolean reset) {
        try {
            /**
             * The FocusListeners bound to some elements of the GUI are temporarly disabled.
             */
            FocusListener[] focusListenersTrainingSet = fieldTrainingSetDirectory.getFocusListeners();
            for (FocusListener FL : focusListenersTrainingSet) {
                fieldTrainingSetDirectory.removeFocusListener(FL);
            }

            FocusListener[] focusListenersStopWords = fieldStopWords.getFocusListeners();
            for (FocusListener FL : focusListenersStopWords) {
                fieldStopWords.removeFocusListener(FL);
            }

            /**
             * The properties of the GUI's elements are set.
             */            //The path of the training set's directory
            trainingSetDirectory = application.getTrainingSetDirectory(reset);
            fieldTrainingSetDirectory.setText(trainingSetDirectory);

            //The current scraper
            String scraperName = application.getScraper(reset).getClass().getName();
            List<Class> scrapers = DocumentClassifierApp.getClassesForPackage(application.getScrapersPackageName());
            if (scrapers.isEmpty()) {
                throw new Exception(preferencesDialogResources.getString("messages.noScraperFound"));
            }
            String currentScraperName;
            for (Class currentScraper : scrapers) {
                currentScraperName = currentScraper.getName();
                if (!currentScraperName.endsWith(".Scraper")) {
                    Class scraperClass = Class.forName(currentScraperName);
                    Object scraperInstance = scraperClass.newInstance();
                    comboBoxScraper.addItem(scraperInstance);
                    if (scraperInstance.getClass().getName().equals(scraperName)) {
                        comboBoxScraper.setSelectedItem(scraperInstance);
                    }
                }
            }

            //If removal of stopwords from documents is enabled or not.
            checkBoxStopWords.setSelected(application.isRemovalStopWords(reset));
            fieldStopWords.setEnabled(checkBoxStopWords.isSelected());

            //The path of the file with the list of stopwords.
            stopWordsList = application.getStopWordsList(reset);
            fieldStopWords.setText(stopWordsList);

            //If stemming of documents' terms is enabled or not.
            checkBoxStemming.setSelected(application.isStemming(reset));
            comboBoxStemmers.setEnabled(checkBoxStemming.isSelected());

            //The current stemmer.
            String stemmerName = application.getStemmer(reset);
            List<Class> stemmers = DocumentClassifierApp.getClassesForPackage(application.getStemmersPackageName());
            if (stemmers.isEmpty() && checkBoxStemming.isSelected()) {
                throw new Exception(preferencesDialogResources.getString("messages.noStemmerFound"));
            }
            String currentStemmerName, currentTrimmedStemmerName;
            for (Class currentStemmer : stemmers) {
                currentStemmerName = currentStemmer.getName();
                currentTrimmedStemmerName = currentStemmerName.substring(currentStemmerName.indexOf("ext.") + 4);
                comboBoxStemmers.addItem(currentTrimmedStemmerName);
                if (currentStemmerName.equals(stemmerName)) {
                    comboBoxStemmers.setSelectedItem(currentTrimmedStemmerName);
                }
            }

            //The current metric.
            if (application.getMetric(reset).equals("TF-IDF")) {
                buttonTFIDF.setSelected(true);
            } else {
                buttonBhattacharrya.setSelected(true);
            }

            //The value of K for the K-NN.
            sliderKNN.setValue(application.getKNN(reset));

            //The maximum value of K for the K-NN, during K-Fold cross validation.
            sliderKNNMaximum.setValue(application.getMaximumKNNValidation(reset));

            //The value of K for the K-Fold cross validation.
            sliderKFold.setValue(application.getKFold(reset));

            //If partitioning for the K-Fold cross validation must be stratified or not.
            checkBoxStratified.setSelected(application.isStratified(reset));

            //If logging during the validation phase is enabled or not.
            checkBoxLogging.setSelected(application.isLogging(reset));

            //The path of the log file.
            logFile = application.getLogFile(reset);
            fieldLogFile.setText(logFile);

            //If the log file must be overwritten each time it is opened.
            checkBoxOverwriteLogFile.setSelected(application.isOverwriteLogFile(reset));

            //If the current document must be visualized during the validation phase.
            checkBoxVisualizeCurrentDocument.setSelected(application.isVisualizeCurrentDocument(reset));

            //If the list of document of the training set, ranked to the query, must be visualized or not during the validation phase.
            checkBoxVisualizeListDocuments.setSelected(application.isVisualizeListRankedDocuments(reset));

            /**
             * The FocusListeners are re-enabled.
             */
            for (FocusListener FL : focusListenersStopWords) {
                fieldStopWords.addFocusListener(FL);
            }

            for (FocusListener FL : focusListenersTrainingSet) {
                fieldTrainingSetDirectory.addFocusListener(FL);
            }

        } catch (Exception ex) {
            DocumentClassifierView.showErrorMessage(ex.toString());
        }
    }

    /**
     * This action is called each time that the user presses the button 'OK'.
     * Its task is to update the values of the preferences, corresponding to those GUI's components whose
     * value or state has been modified by the user.
     */
    @Action
    public void OK() {

        String currentKey;

        currentKey = MapDefaultPreferences.SCRAPER;
        updatePreference(currentKey, mapPreferences.get(currentKey), comboBoxScraper.getSelectedItem().getClass().getName());

        currentKey = MapDefaultPreferences.isREMOVALSTOPWORDS;
        updatePreference(currentKey, mapPreferences.get(currentKey), String.valueOf(checkBoxStopWords.isSelected()));

        if (checkBoxStopWords.isSelected()) {
            checkPath(new FocusEvent(fieldStopWords, FocusEvent.FOCUS_LOST));
        }
        currentKey = MapDefaultPreferences.STOPWORDSLIST;
        updatePreference(currentKey, mapPreferences.get(currentKey), fieldStopWords.getText());

        currentKey = MapDefaultPreferences.isSTEMMING;
        updatePreference(currentKey, mapPreferences.get(currentKey), String.valueOf(checkBoxStemming.isSelected()));

        currentKey = MapDefaultPreferences.STEMMER;
        updatePreference(currentKey, mapPreferences.get(currentKey), application.getStemmersPackageName() + "." + ((String) comboBoxStemmers.getSelectedItem()));

        checkPath(new FocusEvent(fieldTrainingSetDirectory, FocusEvent.FOCUS_LOST));
        currentKey = MapDefaultPreferences.TRAININGSETDIRECTORY;
        updatePreference(currentKey, mapPreferences.get(currentKey), fieldTrainingSetDirectory.getText());

        currentKey = MapDefaultPreferences.METRIC;
        updatePreference(currentKey, mapPreferences.get(currentKey), (buttonTFIDF.isSelected()) ? "TF-IDF" : "Bhattacharrya");

        currentKey = MapDefaultPreferences.KNN;
        updatePreference(currentKey, mapPreferences.get(currentKey), String.valueOf(sliderKNN.getValue()));

        currentKey = MapDefaultPreferences.MAXKNNVALIDATION;
        updatePreference(currentKey, mapPreferences.get(currentKey), String.valueOf(sliderKNNMaximum.getValue()));

        currentKey = MapDefaultPreferences.KFOLD;
        updatePreference(currentKey, mapPreferences.get(currentKey), String.valueOf(sliderKFold.getValue()));

        currentKey = MapDefaultPreferences.isSTRATIFIED;
        updatePreference(currentKey, mapPreferences.get(currentKey), String.valueOf(checkBoxStratified.isSelected()));

        currentKey = MapDefaultPreferences.isLOGGING;
        updatePreference(currentKey, mapPreferences.get(currentKey), String.valueOf(checkBoxLogging.isSelected()));

        currentKey = MapDefaultPreferences.LOGFILE;
        updatePreference(currentKey, mapPreferences.get(currentKey), String.valueOf(fieldLogFile.getText()));

        currentKey = MapDefaultPreferences.isOVERWRITELOGFILE;
        updatePreference(currentKey, mapPreferences.get(currentKey), String.valueOf(checkBoxOverwriteLogFile.isSelected()));

        currentKey = MapDefaultPreferences.isVISUALIZECURRENTDOCUMENT;
        updatePreference(currentKey, mapPreferences.get(currentKey), String.valueOf(checkBoxVisualizeCurrentDocument.isSelected()));

        currentKey = MapDefaultPreferences.isVISUALIZELISTRANKEDDOCUMENTS;
        updatePreference(currentKey, mapPreferences.get(currentKey), String.valueOf(checkBoxVisualizeListDocuments.isSelected()));

        //Once the new values of the modified preferences have been saved, the JDialog is closed.
        dispose();
    }

    /**
     * Action to reset all the preferences to their default value.
     */
    @Action
    public void reset() {
        initializeInterface(true);
    }

    /**
     * This method is called each time that a JFileDialog must be opened, to select
     * a file or directory from the filesystem.
     * 
     * @param evt
     */
private void browse(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_browse
    try {
        JFileChooser fileChooser = new JFileChooser();
        Object source = evt.getSource();
        boolean isTrainingSet = source.equals(buttonBrowseTrainingSetDirectory);
        boolean isStopwordsList = source.equals(buttonBrowseStopWords);
        if (isTrainingSet) {
            fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
            fileChooser.setCurrentDirectory(new File(trainingSetDirectory).getParentFile());
        } else if (isStopwordsList) {
            fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
            fileChooser.setCurrentDirectory(new File(stopWordsList).getParentFile());
            fileChooser.removeChoosableFileFilter(fileChooser.getAcceptAllFileFilter());
            fileChooser.setFileFilter(new FileFilter() {

                @Override
                public boolean accept(File arg) {
                    if (arg.getName().toLowerCase().endsWith(".txt") || arg.isDirectory()) {
                        return true;
                    } else {
                        return false;
                    }
                }

                @Override
                public String getDescription() {
                    return preferencesDialogResources.getString("JFileChooser.textFileType");
                }
            });
        } else {
            fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
            fileChooser.setCurrentDirectory((new File(logFile).getParentFile()));
        }
        if (fileChooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
            String newPath = fileChooser.getSelectedFile().getCanonicalPath();
            if (isTrainingSet && application.generateTrainingSet(newPath)) {
                fieldTrainingSetDirectory.setText(newPath);
                checkPath(new FocusEvent(fieldTrainingSetDirectory, FocusEvent.FOCUS_LOST));
            } else if (isStopwordsList) {
                fieldStopWords.setText(newPath);
                checkPath(new FocusEvent(fieldStopWords, FocusEvent.FOCUS_LOST));
            } else {
                fieldLogFile.setText(newPath);
            }
        }
    } catch (Exception ex) {
        DocumentClassifierView.showErrorMessage(ex.toString());
    }
}//GEN-LAST:event_browse

private void checkBoxStemmingStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_checkBoxStemmingStateChanged
    comboBoxStemmers.setEnabled(checkBoxStemming.isSelected());
}//GEN-LAST:event_checkBoxStemmingStateChanged

private void checkBoxStopWordsStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_checkBoxStopWordsStateChanged
    fieldStopWords.setEnabled(checkBoxStopWords.isSelected());
}//GEN-LAST:event_checkBoxStopWordsStateChanged

    /**
     * This method is called each time that the path specified in one of the JTextFields is modified
     * by the user, and it controls if the new value is valid, that is, if it represents:
     * - A valid stopwords file
     * or
     * - A valid training set directory
     * 
     * @param evt           The FocusEvent generated by the change of focus by one of the JTextFields of the GUI.
     */
private void checkPath(java.awt.event.FocusEvent evt) {//GEN-FIRST:event_checkPath

    JTextField referenceField = (JTextField) evt.getSource();
    String oldPath;
    boolean isTrainingSet = (referenceField == fieldTrainingSetDirectory);
    if (isTrainingSet) {
        oldPath = trainingSetDirectory;
    } else {
        oldPath = stopWordsList;
    }
    String newPath = referenceField.getText();
    if (!newPath.equals(oldPath)) {
        try {
            if (isTrainingSet) {
                //Check of the training set directory
                if (application.generateTrainingSet(newPath)) {
                    trainingSetDirectory = newPath;
                    sliderKNN.setMaximum(application.getKNNMaximum());
                    sliderKNNMaximum.setMaximum(sliderKNN.getMaximum());
                    sliderKFold.setMaximum(application.getKFoldMaximum());
                } else {
                    DocumentClassifierView.showErrorMessage(preferencesDialogResources.getString("messages.invalidTrainingSet"));
                    referenceField.setText(oldPath);
                }
            } else {
                //Check of the file with the list of stopwords
                if (new File(newPath).isFile()) {
                    stopWordsList = newPath;
                } else {
                    DocumentClassifierView.showErrorMessage(preferencesDialogResources.getString("messages.invalidStopWords"));
                    referenceField.setText(oldPath);
                    if (!(new File(oldPath).isFile())) {
                        checkBoxStopWords.setEnabled(false);
                    }
                }
            }
        } catch (Exception ex) {
            DocumentClassifierView.showErrorMessage(ex.toString());
            /**
             * If the new value is not valid, the field that has been checked is reset to its
             * previous value, which instead is supposed to be valid.
             */
            referenceField.setText(oldPath);
        }
    }
}//GEN-LAST:event_checkPath

    /**
     * This method does two things:
     * 1 - Fixes the value of K-Fold, each time that the user enables or disables stratified partitioning.
     * 2 - Fixes the maximum allowed value of K-NN for validation, each time that the user modifies
     * the value of K-Fold.
     * <p>
     * These two tasks are necessary, because:
     * <p>
     * 1 - If stratification is enabled, the set of possible values for
     * K-Fold is restricted, depending on the number of elements of each category of the training set that must
     * be present in each fold.
     * <p>
     * 2 - Analogously, if the user modifies the value of K-Fold (using the appropriate JSlider), the dimension
     * of the current training set at each step changes proportionally, therefore also the maximum allowed value
     * of K-NN changes in accordance.
     * 
     * @param evt
     */
private void fixKFold(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_fixKFold

    int currentKFold = sliderKFold.getValue();
    int trainingSetSize = application.getTrainingSetSize();
    if (checkBoxStratified.isSelected()) {
        final int numberCategories = application.getTrainingSet().size();
        Map<Integer, Integer> possibleKFolds = new HashMap<Integer, Integer>();
        Entry<Integer, Integer> minimumDistance = new AbstractMap.SimpleEntry<Integer, Integer>(0, Integer.MAX_VALUE);
        int i = 1;
        int possibleKFold, currentDistance;
        possibleKFold = trainingSetSize / (numberCategories * i);
        sliderKFold.setMaximum(possibleKFold);
        while (possibleKFold > sliderKFold.getMinimum()) {
            if (!possibleKFolds.containsKey(possibleKFold)) {
                currentDistance = Math.abs(possibleKFold - currentKFold);
                possibleKFolds.put(possibleKFold, currentDistance);
                if (currentDistance < minimumDistance.getValue()) {
                    minimumDistance = new AbstractMap.SimpleEntry<Integer, Integer>(possibleKFold, currentDistance);
                }
            }
            i++;
            possibleKFold = trainingSetSize / (numberCategories * i);
        }
        int newKFold = minimumDistance.getKey();
        sliderKFold.setValue(newKFold);
        sliderKNNMaximum.setMaximum((trainingSetSize / newKFold / numberCategories) * numberCategories * (currentKFold - 1));
    } else {
        sliderKFold.setMaximum(application.getKFoldMaximum());
        sliderKNNMaximum.setMaximum((trainingSetSize / currentKFold) * (currentKFold - 1));
    }
}//GEN-LAST:event_fixKFold

private void checkBoxLoggingItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_checkBoxLoggingItemStateChanged

    boolean isLoggingEnabled = checkBoxLogging.isSelected();
    fieldLogFile.setEnabled(isLoggingEnabled);
    checkBoxOverwriteLogFile.setEnabled(isLoggingEnabled);
}//GEN-LAST:event_checkBoxLoggingItemStateChanged
    // Variables declaration - do not modify//GEN-BEGIN:variables
    javax.swing.JRadioButton buttonBhattacharrya;
    javax.swing.JButton buttonBrowseLogFile;
    javax.swing.JButton buttonBrowseStopWords;
    javax.swing.JButton buttonBrowseTrainingSetDirectory;
    javax.swing.JButton buttonCancel;
    javax.swing.JButton buttonOK;
    javax.swing.JButton buttonReset;
    javax.swing.JRadioButton buttonTFIDF;
    javax.swing.JCheckBox checkBoxLogging;
    javax.swing.JCheckBox checkBoxOverwriteLogFile;
    javax.swing.JCheckBox checkBoxStemming;
    javax.swing.JCheckBox checkBoxStopWords;
    javax.swing.JCheckBox checkBoxStratified;
    javax.swing.JCheckBox checkBoxVisualizeCurrentDocument;
    javax.swing.JCheckBox checkBoxVisualizeListDocuments;
    javax.swing.JComboBox comboBoxScraper;
    javax.swing.JComboBox comboBoxStemmers;
    javax.swing.JTextField fieldLogFile;
    javax.swing.JTextField fieldStopWords;
    javax.swing.JTextField fieldTrainingSetDirectory;
    javax.swing.ButtonGroup groupMetrics;
    javax.swing.JLabel labelCurrentStemmer;
    javax.swing.JLabel labelKFoldTitle;
    javax.swing.JLabel labelKFoldValue;
    javax.swing.JLabel labelKNNMaximumTitle;
    javax.swing.JLabel labelKNNMaximumValue;
    javax.swing.JLabel labelKNNTitle;
    javax.swing.JLabel labelKNNValue;
    javax.swing.JLabel labelLogFile;
    javax.swing.JLabel labelMetric;
    javax.swing.JLabel labelPreprocessing;
    javax.swing.JLabel labelScraper;
    javax.swing.JLabel labelStopWords;
    javax.swing.JLabel labelTrainingSetDirectory;
    javax.swing.JPanel panelClassification;
    javax.swing.JPanel panelPreprocessing;
    javax.swing.JPanel panelTrainingSet;
    javax.swing.JPanel panelValidation;
    javax.swing.JSeparator separatorKFoldLogging;
    javax.swing.JSeparator separatorKNNMaximumKFold;
    javax.swing.JSeparator separatorLogFileVisualize;
    javax.swing.JSeparator separatorMetricKNN;
    javax.swing.JSeparator separatorScraperPreprocessing;
    javax.swing.JSlider sliderKFold;
    javax.swing.JSlider sliderKNN;
    javax.swing.JSlider sliderKNNMaximum;
    javax.swing.JTabbedPane tabbelPanePreferences;
    private org.jdesktop.beansbinding.BindingGroup bindingGroup;
    // End of variables declaration//GEN-END:variables
}
